import { useVueFlow } from '@vue-flow/core'
import { ref, watch } from 'vue'

// let id = 0

/**
 * 返回一个自增ID
 */
// function getId() {
//   return id++
// }

/**
 * In a real world scenario you'd want to avoid creating refs in a global scope like this as they might not be cleaned up properly.
 * 在真实世界的场景中，您希望避免在这样的全局范围内创建引用，因为它们可能不会被正确清理。
 * @type {{draggedType: Ref<string|null>, isDragOver: Ref<boolean>, isDragging: Ref<boolean>}}
 */
const state = {
  /**
   * The type of the node being dragged.
   */
  draggedType: ref(null),
  draggedName: ref(null),
  isDragOver: ref(false),
  isDragging: ref(false),
}

export default function useDragAndDrop() {
  // 解构赋值
  const { draggedType, draggedName, isDragOver, isDragging } = state
  // 解构函数
  const { addNodes, screenToFlowCoordinate, onNodesInitialized, updateNode } = useVueFlow()
  // 监听`isDragging`的值
  watch(isDragging, (dragging) => {
    document.body.style.userSelect = dragging ? 'none' : ''
  })

  /** 1. 拖拽开始 */
  function onDragStart(event, type, name) {
    // console.log('拖拽开始')
    if (event.dataTransfer) {
      event.dataTransfer.setData('application/vueflow', type)
      event.dataTransfer.effectAllowed = 'move'
    }

    draggedType.value = type
    draggedName.value = name
    isDragging.value = true
    // 监听`drop`, `drop`触发时调用`onDragEnd`拖拽结束
    document.addEventListener('drop', onDragEnd)
  }

  /** 2. 拖拽置于background上 */
  function onDragOver(event) {
    // console.log('拖拽置于background上')
    event.preventDefault()
    if (draggedType.value) {
      isDragOver.value = true

      if (event.dataTransfer) {
        event.dataTransfer.dropEffect = 'move'
      }
    }
  }

  /** 3. 拖拽离开background */
  function onDragLeave() {
    // console.log('拖拽离开background')
    isDragOver.value = false
  }

  /** 4. 拖拽结束 */
  function onDragEnd() {
    // console.log('拖拽结束')
    isDragging.value = false
    isDragOver.value = false
    draggedType.value = null
    draggedName.value = null
    // 取消监听
    document.removeEventListener('drop', onDragEnd)
  }

  /** 5. 拖拽松开 */
  function onDrop(event) {
    // console.log('拖拽松开')
    // 获取xy坐标
    const position = screenToFlowCoordinate({
      x: event.clientX,
      y: event.clientY,
    })
    // 节点ID
    let nodeId = undefined
    // label
    let label = undefined
    switch (draggedType.value) {
      case 'custom-input':
        nodeId = 'start'
        label = '开始'
        break
      case 'custom-output':
        nodeId = 'end'
        label = '结束'
        break
      case 'custom1':
      case 'custom2':
        nodeId = `${draggedName.value}_${new Date().getTime()}`
        label = draggedName.value
        break
    }
    // 声明新新节点
    const newNode = {
      id: nodeId,
      type: draggedType.value,
      position,
      label,
      data: {
        description: label
      }
    }

    /**
     * Align node position after drop, so it's centered to the mouse
     * 放置后对齐节点位置，使其居中于鼠标
     *
     * We can hook into events even in a callback, and we can remove the event listener after it's been called.
     * 我们甚至可以在回调中钩住事件，并且可以在调用事件监听器后将其删除。
     */
    const { off } = onNodesInitialized(() => {
      updateNode(nodeId, (node) => ({
        position: { x: node.position.x - node.dimensions.width / 2, y: node.position.y - node.dimensions.height / 2 },
      }))

      off()
    })
    // 创建新节点
    addNodes(newNode)
  }

  return {
    draggedType,
    draggedName,
    isDragOver,
    isDragging,
    onDragStart,
    onDragLeave,
    onDragOver,
    onDrop,
  }
}